using Magiq.Behaviors;
using Magiq.Insert;
using Magiq.Objects;
using Magiq.Support;

namespace Magiq.Databases.SqlServer
{
    public class BulkCopy : MagiqBehavior, IObjectsInsertBehavior, IInsertBehavior
    {
        public int BatchSize { get; set; }
        public int Timeout { get; set; }

        public BulkCopy()
        {
            BatchSize = 0;
            Timeout = 30;
        }

        private static bool Applies(IDatabaseBasedExecution execution)
        {
            return execution != null && execution.DatabaseAdapter.Dialect is SqlServerDialect;
        }
        
        public IInsertDestination<TNew> GetInsertDestination<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert)
            where TDestination : class
            where TNew : class, TDestination, new()
        {
            var insertDestination = Next<IObjectsInsertBehavior>().Call(x => x.GetInsertDestination(insert));
            var databaseOperation = insertDestination as IDatabaseBasedExecution;

            if (Applies(databaseOperation))
                return new BulkCopyDestination<TSource, TDestination, TNew>(insert, databaseOperation.DatabaseAdapter)
                           {
                               BatchSize = BatchSize,
                               Timeout = Timeout
                           };

            return insertDestination;
        }

        public IInsertStrategy GetInsertStrategy<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert) where TDestination : class where TNew : class, TDestination, new()
        {
            var strategy = Next<IInsertBehavior>().Call(x => x.GetInsertStrategy(insert));
            var databaseOperation = strategy as IDatabaseBasedExecution;

            if (Applies(databaseOperation))
                return new InsertStrategy<TSource, TDestination, TNew>(insert);

            //overrides the strategy with magiq-to-objects
            return strategy;
        }

        public int Execute(IInsertStrategy strategy)
        {
            //default behavior
            return Next<IInsertBehavior>().Call(x => x.Execute(strategy));
        }
    }
}